package lz.controls
{	
	import flash.events.MouseEvent;
	
	import lz.controls.core.InvalidationType;
	import lz.controls.core.UIComponent;
	import lz.controls.events.ComponentEvent;
	import lz.controls.events.ScrollEvent;
	/**
	 *当数据太多以至于显示区域无法容纳时，最终用户可以使用 ScrollBar 组件控制所显示的数据部分。 
	 * 滚动条由四部分组成：两个箭头按钮、一个轨道和一个滑块。
	 *  滑块的位置和显示的按钮取决于滚动条的当前状态。 
	 * 滚动条使用四个参数来计算其显示状态：
	 * 一个最小范围值、一个最大范围值、一个必须位于范围值内的当前位置和一个视域大小
	 * 视域大小必须小于等于该范围，它表示在该范围内一次可以显示的项目数。
	 */
	public class ScrollBar extends UIComponent 
	{
        /**
         *滚动条宽度
		 */
		public static var WIDTH:Number = 15;
	
		/**
		 * 
		 */
		protected var _pageSize:Number = 10;
		/**
         * @private
		 */
		private var _pageScrollSize:Number = 0;
		/**
         * @private
		 */
		private var _lineScrollSize:Number = 1;
		/**
		 * 最低滚动位置的数字。
		 */
		private var _minScrollPosition:Number = 0;
		/**
		 * 最高滚动位置的数字。
		 */
		private var _maxScrollPosition:Number = 0;
		/**
		 * 滚动位置
		 */
		private var _scrollPosition:Number = 0;
		/**
		 * 方向 横或竖
		 */
		private var _direction:String = ScrollBarDirection.VERTICAL;
		/**
         * @private
		 */
		protected var thumbScrollOffset:Number;
		/**
         * @private
		 */
		protected var inDrag:Boolean = false;
		/**
		 * 向上按钮
		 */
		protected var upArrow:BaseButton;
		/**
		 * 向下按钮
		 */
		protected var downArrow:BaseButton;
		/**
		 * 滑块
		 */
		protected var thumb :BaseButton;
		/**
		 * 滑槽
		 */
		protected var track:BaseButton;
		/**
		 * 默认样式
		 */
		private static var defaultStyles:Object = {downArrowDisabledSkin:"ScrollArrowDown_disabledSkin",downArrowDownSkin:"ScrollArrowDown_downSkin",downArrowOverSkin:"ScrollArrowDown_overSkin",downArrowUpSkin:"ScrollArrowDown_upSkin",
													 thumbDisabledSkin:"ScrollThumb_upSkin",thumbDownSkin:"ScrollThumb_upSkin",thumbOverSkin:"ScrollThumb_overSkin",thumbUpSkin:"ScrollThumb_upSkin",
													 trackDisabledSkin:"ScrollTrack_skin",trackDownSkin:"ScrollTrack_skin",trackOverSkin:"ScrollTrack_skin",trackUpSkin:"ScrollTrack_skin",
													 upArrowDisabledSkin:"ScrollArrowUp_disabledSkin",upArrowDownSkin:"ScrollArrowUp_downSkin",upArrowOverSkin:"ScrollArrowUp_overSkin",upArrowUpSkin:"ScrollArrowUp_upSkin",
													 thumbIcon:"ScrollBar_thumbIcon",
													 repeatDelay:500,repeatInterval:35};
        /**
         *检索当前组件的默认样式映射
         */
		public static function getStyleDefinition():Object
		{ 
			return defaultStyles;
		}
		
		
		/**
		 * 向下按钮样式 
		 */
		protected static const DOWN_ARROW_STYLES:Object = {
												disabledSkin:"downArrowDisabledSkin",
												downSkin:"downArrowDownSkin",
												overSkin:"downArrowOverSkin",
												upSkin:"downArrowUpSkin",
												repeatDelay:"repeatDelay",
												repeatInterval:"repeatInterval"
												};
		/**
		 * 滑块按钮样式 
		 */
		protected static const THUMB_STYLES:Object = {
												disabledSkin:"thumbDisabledSkin",
												downSkin:"thumbDownSkin",
												overSkin:"thumbOverSkin",
												upSkin:"thumbUpSkin",
												icon:"thumbIcon",
												textPadding: 0
												};
		/**
		 * 槽样式
		 */
		protected static const TRACK_STYLES:Object = {
												disabledSkin:"trackDisabledSkin",
												downSkin:"trackDownSkin",
												overSkin:"trackOverSkin",
												upSkin:"trackUpSkin",
												repeatDelay:"repeatDelay",
												repeatInterval:"repeatInterval"
												};
		/**
		 * 向下按钮样式 
		 */
		protected static const UP_ARROW_STYLES:Object = {
												disabledSkin:"upArrowDisabledSkin",
												downSkin:"upArrowDownSkin",
												overSkin:"upArrowOverSkin",
												upSkin:"upArrowUpSkin",
												repeatDelay:"repeatDelay",
												repeatInterval:"repeatInterval"
												};
		
		
		/**
         *创建新的 ScrollBar 组件实例。
		 */
		public function ScrollBar() 
		{
			super();
			setStyles();
			focusEnabled = false;
		}
		
		/**
		 * 设置滚动条样式大小
		 */
		override public function setSize(width:Number, height:Number):void
		{
			if (_direction == ScrollBarDirection.HORIZONTAL) 
			{
				super.setSize(height,width);
			} else
			{
				super.setSize(width,height);
			}
		}
		
		/**
         * @copy UIComponent#width
         *
         * @see #height
         * @see #setSize()
		 */
		override public function get width():Number 
		{
			return (_direction == ScrollBarDirection.HORIZONTAL) ? super.height : super.width;
		}
		
		/**
         * @copy UIComponent#height
         *
         * @see #setSize()
         * @see #width
		 */
		override public function get height():Number 
		{
			return (_direction == ScrollBarDirection.HORIZONTAL) ? super.width : super.height;
		}
		
		/**
		 * 指示是否启用滚动条
         * @default true
		 */
		override public function get enabled():Boolean
		{
			return super.enabled;
		}
		/**
		 * 指示是否启用滚动条
         * @private (setter)
		 */
		override public function set enabled(value:Boolean):void 
		{
			super.enabled = value;
			if(downArrow == null)
			{
				return;
			}
			downArrow.enabled = track.enabled = thumb.enabled = upArrow.enabled = (enabled && _maxScrollPosition > _minScrollPosition);
			updateThumb();
		}
		
		/**
		 * 设置 ScrollBar 组件的范围和视口大小。 
		 * ScrollBar 组件会相应地更新箭头按钮的状态和滚动滑块的大小。
		 * 所有滚动属性是相对于 minScrollPosition 和 maxScrollPosition 的缩放而言的。
		 * 介于最大值和最小值之间的每个数字都代表一个滚动位置。
		 * 	pageSize:Number — 一个页面的大小。 确定滑块的大小以及单击箭头时滚动条移动的增量。
		 * 	minScrollPosition:Number — 滚动范围的底部。
		 * 	maxScrollPosition:Number — 滚动范围的顶部。
		 * 	pageScrollSize:Number (default = 0) — 单击轨道时移动的增量，以像素为单位。
		 */
		public function setScrollProperties(pageSize:Number,
											minScrollPosition:Number,
											maxScrollPosition:Number,
											pageScrollSize:Number=0):void 
		{
			this.pageSize = pageSize;
			_minScrollPosition = minScrollPosition;
			_maxScrollPosition = maxScrollPosition;
			if (pageScrollSize >= 0) { _pageScrollSize = pageScrollSize; }
			enabled = (_maxScrollPosition > _minScrollPosition);
			// ensure our scroll position is still in range:
			setScrollPosition(_scrollPosition, false);
			updateThumb();
		}
		
		/**
		 * 滚动位置 
         * @default 0
		 */
		public function get scrollPosition():Number { return _scrollPosition; }
		
		
		/**
		 * 滚动位置 
		 */
		public function set scrollPosition(newScrollPosition:Number):void
		{
			setScrollPosition(newScrollPosition, true);
		}
		
		/**
		 * 最小滚动 位置 
         * @default 0
		 */
		public function get minScrollPosition():Number 
		{
			return _minScrollPosition;
		}		
		
		/**
		 * 最小滚动 位置 
         * @private (setter)
		 */
		public function set minScrollPosition(value:Number):void 
		{
			// This uses setScrollProperties because it needs to update thumb and enabled.
			setScrollProperties(_pageSize,value,_maxScrollPosition);
		}
		
		/**
		 * 最大的滚动位置 
         * @default 0
		 */
		public function get maxScrollPosition():Number 
		{
			return _maxScrollPosition;
		}		
		
		/**
		 * 最大的滚动位置 
		 */
		public function set maxScrollPosition(value:Number):void
		{
			// This uses setScrollProperties because it needs to update thumb and enabled.
			setScrollProperties(_pageSize,_minScrollPosition,value);
		}
		
		/**
		 * 页中所包含的行数
		 */
		public function get pageSize():Number
		{
			return _pageSize;
		}
		
		/**所包含的行数。
		 */
		public function set pageSize(value:Number):void 
		{
			if (value > 0) 
			{
				_pageSize = value;
			}
		}
		/**
		 * 表示按下滚动条轨道时页面滚动的增量
		 */
		public function get pageScrollSize():Number 
		{
			return (_pageScrollSize == 0) ? _pageSize : _pageScrollSize;
		}
		/**
		 * 表示按下滚动条轨道时页面滚动的增量
		 */
		public function set pageScrollSize(value:Number):void 
		{
			if (value>=0) { _pageScrollSize = value; }
		}
		
		/**
		 * 表示按下滚动条轨道时页面滚动的增量。
		 */
		public function get lineScrollSize():Number 
		{
			return _lineScrollSize;
		}		
		
		/**
		 * 表示按下滚动条轨道时页面滚动的增量。
         * @private (setter)
		 */
		public function set lineScrollSize(value:Number):void 
		{
			if (value>0) {_lineScrollSize = value; }
		}
		
		/**
		 * 获取滚动条方向
		 */
		public function get direction():String 
		{
			return _direction;
		}
		
		/**
		 * 设置滚动位置（横向还是竖向）
		 */
		public function set direction(value:String):void 
		{
			if (_direction == value) { return; }
			_direction = value;
			if (isLivePreview) { return; } // Rotation and scaling happens automatically in LivePreview.
			//
			setScaleY(1);			
			
			var horizontal:Boolean = _direction == ScrollBarDirection.HORIZONTAL;
			if (horizontal && componentInspectorSetting) 
			{
				if (rotation == 90 ) { return; }
				setScaleX(-1);
				rotation = -90;
			}
			
			if (!componentInspectorSetting) 
			{
				if (horizontal && rotation == 0) 
				{
					rotation = -90;
					setScaleX(-1);
				} else if (!horizontal && rotation == -90 ) 
				{
					rotation = 0;
					setScaleX(1);
				}
			}
			invalidate(InvalidationType.SIZE);
		}
		
		/**
		 * 初始化
         * @private (protected)
		 */		
		override protected function configUI():void 
		{
			super.configUI();
			
			track = new BaseButton();
			track.move(0,15);
			track.useHandCursor = false;
			track.autoRepeat = true;
			track.focusEnabled = false;
			addChild(track);
			
			thumb = new BaseButton();
			thumb.setSize(WIDTH,15);
			thumb.move(0,15);
			thumb.focusEnabled = false;
			addChild(thumb);
			
			downArrow = new BaseButton();
			downArrow.setSize(WIDTH,15);
			downArrow.autoRepeat = true;
			downArrow.focusEnabled = false;
			addChild(downArrow);
			
			upArrow = new BaseButton();
			upArrow.setSize(WIDTH,15);
			upArrow.autoRepeat = true;
			upArrow.focusEnabled = false;
			addChild(upArrow);
			
			upArrow.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
			downArrow.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
			track.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
			thumb.addEventListener(MouseEvent.MOUSE_DOWN,thumbPressHandler,false,0,true);
			
			enabled = false;
		}
		
		/**
		 * 重画
         * @private (protected)
		 */
		override protected function draw():void 
		{	
			if(downArrow == null)
			{
				return ;
			}
			if (isInvalid(InvalidationType.SIZE)) 
			{
				var h:Number = super.height;
				downArrow.move(0,  (Math.max(upArrow.height, h-downArrow.height)));
				track.setSize(WIDTH, (Math.max(0, h - (downArrow.height + upArrow.height))));
				updateThumb();
			}
			if (isInvalid(InvalidationType.STYLES,InvalidationType.STATE))
			{
				setStyles();
			}
			//trace(this.width,this.height);
			// Call drawNow on nested components to get around problems with nested render events:
			downArrow.drawNow();
			upArrow.drawNow();
			track.drawNow();
			thumb.drawNow();
			validate();
		}
		
		/**
		 * 点击事件
         * @private (protected)
		 */
		protected function scrollPressHandler(event:ComponentEvent):void 
		{
			event.stopImmediatePropagation();
			if (event.currentTarget == upArrow) 
			{
				setScrollPosition(_scrollPosition-_lineScrollSize); 
			} else if (event.currentTarget == downArrow)
			{
				setScrollPosition(_scrollPosition+_lineScrollSize);
			} else
			{
				var mousePosition:Number = (track.mouseY)/track.height * (_maxScrollPosition-_minScrollPosition) + _minScrollPosition;
				var pgScroll:Number = (pageScrollSize == 0)?pageSize:pageScrollSize;
				if (_scrollPosition < mousePosition) 
				{
					setScrollPosition(Math.min(mousePosition,_scrollPosition+pgScroll));
				} else if (_scrollPosition > mousePosition) 
				{
					setScrollPosition(Math.max(mousePosition,_scrollPosition-pgScroll));
				}
			}
		}
		/**
         * 滑块按下事件
		 */
		protected function thumbPressHandler(event:MouseEvent):void 
		{
			inDrag = true;
			thumbScrollOffset = mouseY-thumb.y;
			thumb.mouseStateLocked = true;
			mouseChildren = false; // Should be able to do stage.mouseChildren, but doesn't seem to work.
			stage.addEventListener(MouseEvent.MOUSE_MOVE,handleThumbDrag,false,0,true);
			stage.addEventListener(MouseEvent.MOUSE_UP,thumbReleaseHandler,false,0,true);
		}
		/**
		 * 处理滑块拖动事件
         * @private (protected)
		 */
		protected function handleThumbDrag(event:MouseEvent):void 
		{
			var pos:Number = Math.max(0, Math.min(track.height-thumb.height, mouseY-track.y-thumbScrollOffset));
			setScrollPosition(pos/(track.height-thumb.height) * (_maxScrollPosition-_minScrollPosition) + _minScrollPosition);
		}
		/**
		 * 处理滑块松开事件
		 */
		protected function thumbReleaseHandler(event:MouseEvent):void 
		{
			inDrag = false;
			mouseChildren = true;
			thumb.mouseStateLocked = false;
			stage.removeEventListener(MouseEvent.MOUSE_MOVE,handleThumbDrag);
			stage.removeEventListener(MouseEvent.MOUSE_UP,thumbReleaseHandler);
		}
		/**
		 * 设置滚动位置
		 */
		public function setScrollPosition(newScrollPosition:Number, fireEvent:Boolean=true):void
		{
			var oldPosition:Number = scrollPosition;
			_scrollPosition = Math.max(_minScrollPosition,Math.min(_maxScrollPosition, newScrollPosition));
			if (oldPosition == _scrollPosition) { return; }
			if (fireEvent) { dispatchEvent(new ScrollEvent(_direction, scrollPosition-oldPosition, scrollPosition)); }
			updateThumb();
		}
		/**
		 * 设置样式
         * @private (protected)
		 */
		protected function setStyles():void 
		{
			copyStylesToChild(downArrow,DOWN_ARROW_STYLES);
			copyStylesToChild(thumb,THUMB_STYLES);
			copyStylesToChild(track,TRACK_STYLES);
			copyStylesToChild(upArrow,UP_ARROW_STYLES);
		}
		/**
		 * 更新滑块位置和大小
         * @private
		 */
		protected function updateThumb():void 
		{
			var per:Number = _maxScrollPosition - _minScrollPosition + _pageSize;
			if (track.height <= 12 
				|| _maxScrollPosition <= _minScrollPosition 
				|| (per == 0 || isNaN(per))) 
			{
				thumb.height = 12;
				thumb.visible = false;
			} else 
			{
				thumb.height = Math.max(13,_pageSize / per * track.height);
				thumb.y = track.y+(track.height-thumb.height)*((_scrollPosition-_minScrollPosition)/(_maxScrollPosition-_minScrollPosition));
				thumb.visible = enabled;
			}
		}
	}
}
